package com.hex.ds.hdrs.agent.service;

import cn.hutool.core.collection.CollectionUtil;
import com.hex.ds.hdrs.agent.po.AgentConf;
import com.hex.ds.hdrs.agent.vo.AgentServerVo;
import com.hex.ds.hdrs.center.po.CenterConf;
import com.hex.ds.hdrs.center.service.CenterConfService;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.constant.ErrorCode;
import com.hex.ds.hdrs.common.exception.BizException;
import com.hex.ds.hdrs.common.utils.BaseUtil;
import com.hex.ds.hdrs.common.utils.HdrsDateUtil;
import com.hex.ds.hdrs.period.task.service.PeriodTaskService;
import com.hex.ds.ra.common.base.BaseRespInfo;
import com.hex.ds.ra.model.AgentInfModel;
import com.hex.ds.ra.model.BizAgentModel;
import com.hex.ds.ra.model.dto.AgentInfDto;
import com.hex.ds.ra.service.AgentInfService;
import com.hex.ds.ra.service.BizAgentService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author lwz
 * @date 2021-06-23
 * @des
 */
@Slf4j
@Service
public class RemoteAgentService {

    @Value("${center.centerIp}")
    private String centerIp;

    @Value("${server.port}")
    private int port;

    @Autowired
    private BizAgentService bizAgentService;

    @Autowired
    private AgentInfService agentInfService;

    @Autowired
    private AgentConfService agentConfService;

    @Autowired
    private AgentManager agentManager;

    @Autowired
    private CenterConfService centerConfService;
    @Autowired
    private PeriodTaskService periodTaskService;


    @Transactional
    public void add(AgentConf agentConf) {
        log.info("进入了AgentConfService类中的add方法");
        checkName(agentConf);
        this.initAgentConf(agentConf);
        this.agentConfService.add(agentConf);
    }

    private void initAgentConf(AgentConf agentConf) {
        agentConf.setUpTs(HdrsDateUtil.getCurrentTime());
        agentConf.setPkId(BaseUtil.getPkId());
        agentConf.setCrtUser(BaseUtil.getUserId());
        agentConf.setUpUser(BaseUtil.getUserId());
        //初始化状态都是未开启
        agentConf.setAgentStatus(Const.AGENT_DEFAULT_STATUS);
        agentConf.setAgentHaStatus(Const.AGENT_HA_STATUS_STOP);
        //封装agentCode
        String agentCode = "AG" + BaseUtil.getPkId().substring(0, 5).toUpperCase();
        agentConf.setAgentCode(agentCode);
    }

    @Transactional
    public void saveAndInstall(AgentConf agentConf) {
        log.info("进入了AgentConfService类中的saveAndInstall方法");
        // 1.添加agent
        add(agentConf);
        // 2.发布调度服务
        this.install(agentConf);
    }

    private void install(AgentConf agentConf) {
        BizAgentModel model = this.buildbBzAgentModel(agentConf);
        this.setInstallParam(model);
        BaseRespInfo respInfo = this.bizAgentService.install(model);

        // 3.发布成功后更新调度服务状态
        if (com.hex.ds.ra.common.constant.Const.HTTP_STATUS_OK.equals(respInfo.getCode())) {
            agentConf.setAgentStatus(Const.AGENT_ENABLE_STATUS);
            this.agentConfService.update(agentConf);
        } else {
            throw new BizException(ErrorCode.ERROR_870000.getCode(), respInfo.getMsg());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveAll(AgentServerVo agentServerVo) {
        log.info("进入了AgentConfService类中的saveAndInstall方法");
        // 1.保存管理AGENT配置
        AgentInfModel agentInfModel = agentServerVo.getAgentInfModel();
        agentInfModel.setCrtUser(BaseUtil.getUserName());
        agentInfModel.setUpUser(BaseUtil.getUserName());
        this.agentInfService.add(agentInfModel);

        // 2.保存调度服务配置信息
        this.agentConfService.add(agentServerVo.getAgentConf());
    }

    @SneakyThrows
    public void saveAndInstallAll(AgentServerVo agentServerVo) {
        log.info("进入了AgentConfService类中的saveAndInstall方法");
        // 1.保存管理AGENT和调度服务的配置信息
        this.saveAll(agentServerVo);

        // 2.发布管理AGENT
        AgentInfDto agentInfDto = new AgentInfDto();
        agentInfDto.setAgentInfModel(agentServerVo.getAgentInfModel());
        agentInfDto.setOptUser(BaseUtil.getUserName());
        this.agentInfService.install(agentInfDto);

        // 3.发布调度服务
        this.installServer(agentServerVo);
    }

    @SneakyThrows
    private void installServer(AgentServerVo agentServerVO) {
        boolean isInstallServer = false;
        Thread.sleep(5000);
        for (int i = 0; i < 3; i++) {
            if (!isInstallServer && this.checkAgentConnect(agentServerVO.getAgentInfModel())) {
                isInstallServer = true;
                this.install(agentServerVO.getAgentConf());
            }
        }
        if (!isInstallServer) {
            throw new Exception("安装调度服务失败:无法连接AGENT，请查看AGENT端口是否对外开放或稍后再尝试安装");
        }
    }

    private boolean checkAgentConnect(AgentInfModel agentInfModel) {
        BizAgentModel bizAgentModel = new BizAgentModel();
        bizAgentModel.setAppType(Const.AGENT_NAME);
        bizAgentModel.setAgentHost(agentInfModel.getAgentIp());
        bizAgentModel.setAgentPort(agentInfModel.getAgentPort());
        bizAgentModel.setAgentCode(agentInfModel.getAgentCode());
        bizAgentModel.setAgentName(agentInfModel.getAgentName());
        bizAgentModel.setVersion(agentInfModel.getServerVer());
        bizAgentModel.setOptUser(BaseUtil.getUserName());
        BaseRespInfo respInfo = this.agentInfService.checkConnect(bizAgentModel);
        return com.hex.ds.ra.common.constant.Const.HTTP_STATUS_OK.equals(respInfo.getCode());
    }


    private BizAgentModel buildbBzAgentModel(AgentConf agentConf) {
        BizAgentModel bizAgentModel = new BizAgentModel();
        bizAgentModel.setAppType(Const.AGENT_NAME);
        bizAgentModel.setActName(Const.AGENT_INSTALL);
        bizAgentModel.setAgentHost(agentConf.getAgentIp());
        bizAgentModel.setAgentPort(agentConf.getAgentPort());
        bizAgentModel.setAgentCode(agentConf.getAgentCode());
        bizAgentModel.setAgentName(agentConf.getAgentName());
        bizAgentModel.setVersion(agentConf.getServerVer());
        bizAgentModel.setOptUser(BaseUtil.getUserName());
        return bizAgentModel;
    }

    public BaseRespInfo install(BizAgentModel bizAgentModel) {
        bizAgentModel.setOptUser(BaseUtil.getUserName());
        // 设置AGENT自动发布启动脚本参数
        this.setInstallParam(bizAgentModel);
        BaseRespInfo respInfo = this.bizAgentService.install(bizAgentModel);

        if (com.hex.ds.ra.common.constant.Const.HTTP_STATUS_OK.equals(respInfo.getCode())) {
            this.agentConfService.updateAgentStatus(bizAgentModel.getAgentCode(), Const.AGENT_ENABLE_STATUS);
        } else {
            this.agentConfService.updateAgentStatus(bizAgentModel.getAgentCode(), Const.AGENT_INSTALL_FAIL_STATUS);
        }
        return respInfo;
    }

    public BaseRespInfo start(BizAgentModel bizAgentModel) {
        AgentSession agentSession = agentManager.getSession(bizAgentModel.getAgentCode());
        if (null != agentSession) {
            agentSession.setStatus(Const.AGENT_STATUS_START);
        }
        bizAgentModel.setOptUser(BaseUtil.getUserName());
        BaseRespInfo respInfo = this.bizAgentService.start(bizAgentModel);
        if (com.hex.ds.ra.common.constant.Const.HTTP_STATUS_OK.equals(respInfo.getCode())) {
            this.agentConfService.updateAgentStatus(bizAgentModel.getAgentCode(), Const.AGENT_ENABLE_STATUS);
        }
        return respInfo;
    }

    public BaseRespInfo stop(BizAgentModel bizAgentModel) {
        bizAgentModel.setOptUser(BaseUtil.getUserName());
        BaseRespInfo respInfo = this.bizAgentService.stop(bizAgentModel);
        if (com.hex.ds.ra.common.constant.Const.HTTP_STATUS_OK.equals(respInfo.getCode())) {
            this.agentConfService.updateAgentStatus(bizAgentModel.getAgentCode(), Const.AGENT_STOP_STATUS);
            // 将对应正在执行的任务重跑
            periodTaskService.updateRunning2ToDo(bizAgentModel.getAgentCode());
        }
        // 停用agent，删除agentSession
        AgentSession agentSession = agentManager.getAgentSession(bizAgentModel.getAgentCode());
        agentManager.delAgentSession(agentSession);
        return respInfo;
    }

    public BaseRespInfo restart(BizAgentModel bizAgentModel) {
        bizAgentModel.setOptUser(BaseUtil.getUserName());
        BaseRespInfo respInfo = this.bizAgentService.restart(bizAgentModel);
        if (com.hex.ds.ra.common.constant.Const.HTTP_STATUS_OK.equals(respInfo.getCode())) {
            this.agentConfService.updateAgentStatus(bizAgentModel.getAgentCode(), Const.AGENT_ENABLE_STATUS);
            // 将对应正在执行的任务重跑
            periodTaskService.updateRunning2ToDo(bizAgentModel.getAgentCode());
        }
        return respInfo;
    }

    private void setInstallParam(BizAgentModel bizAgentModel) {
        Map dataMap = bizAgentModel.getDataMap();
        if (CollectionUtil.isEmpty(dataMap)) {
            dataMap = new HashMap();
        }
        //获取中心ip集合传到agent
        Map map = new HashMap(16);
        String centerIps = "";
        List<CenterConf> centerConfs = centerConfService.qryList(map);
        for (int i = 0; i < centerConfs.size(); i++) {
            if (i == centerConfs.size() - 1) {
                centerIps += "http://" + centerConfs.get(i).getCenterIp();
            } else {
                centerIps += "http://" + centerConfs.get(i).getCenterIp() + ",";
            }
        }
        String installParam = centerIps + " " + port + " " + bizAgentModel.getAgentCode()
                + " " + bizAgentModel.getAgentName() + " " + bizAgentModel.getAgentHost() + " "
                + bizAgentModel.getAgentPort();
        dataMap.put("installParam", installParam);
        bizAgentModel.setDataMap(dataMap);
    }

    public BaseRespInfo upgrade(BizAgentModel bizAgentModel) {
        bizAgentModel.setOptUser(BaseUtil.getUserName());
        this.setInstallParam(bizAgentModel);
        BaseRespInfo respInfo = this.bizAgentService.upgrade(bizAgentModel);

        if (com.hex.ds.ra.common.constant.Const.HTTP_STATUS_OK.equals(respInfo.getCode())) {
            this.agentConfService.updateAgentVersion(bizAgentModel.getAgentCode(), String.valueOf(bizAgentModel.getDataMap().get("newVersion")));
        }
        return respInfo;
    }

    public BaseRespInfo restore(BizAgentModel bizAgentModel) {
        bizAgentModel.setOptUser(BaseUtil.getUserName());
        BaseRespInfo respInfo = this.bizAgentService.restore(bizAgentModel);
        if (com.hex.ds.ra.common.constant.Const.HTTP_STATUS_OK.equals(respInfo.getCode())) {
            this.agentConfService.updateAgentVersion(bizAgentModel.getAgentCode(), bizAgentModel.getVersion());
        }
        return respInfo;
    }

    public void checkName(AgentConf agentConf) {
        if (StringUtils.isBlank(agentConf.getAgentName())) {
            throw new BizException(ErrorCode.ERROR_870001);
        }
        AgentConf dbAgentConf = this.agentConfService.qryAgentConfByName(agentConf.getAgentName());
        if (dbAgentConf != null && !dbAgentConf.getPkId().equals(agentConf.getPkId())) {
            throw new BizException(ErrorCode.ERROR_870002);
        }
    }
}
